Add Todo
//todo Reducer
const todo = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return {
id: action.id,
text: action.text,
completed: false
};
case 'TOGGLE_TODO':
if (state.id !== action.id) {
return state;
}
return {
...state,
completed: !state.completed
};
default:
return state;
}
};
//todos Reducer
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
todo(undefined, action)
];
case 'TOGGLE_TODO':
return state.map(t => todo(t, action));
default:
return state;
}
};
const visibilityFilter = (state = 'SHOW_ALL',
action) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter;
default:
return state;
}
};
let nextTodoId = 0;
const { createStore, combineReducers } = Redux;
const todoApp = combineReducers({todos,visibilityFilter});
const store = createStore(todoApp);
const { Component } = React;
class TodoApp extends Component {
render() {
return (
<div>
<input ref={node => {
this.input = node;
}} />
<button onClick={() => {
store.dispatch({
type: 'ADD_TODO',
text: this.input.value,
id: nextTodoId++
});
}}>
Add Todo
</button>
<ul>
{this.props.todos.map(todo =>
<li key={todo.id}>
{todo.text}
</li>
)}
</ul>
</div>
);
};
};
const render = () => {
ReactDOM.render(
<TodoApp todos={store.getState().todos} />,
document.getElementById('root')
);
};
store.subscribe(render);
render();
//最终代码: http://jsbin.com/zulokux/edit?js,output
Toggling a Todo
<li key={todo.id} >
{todo.text}
</li>
//...*/
// 修改后
<li key={todo.id}
onClick={() =>{
store.dispatch({
type: 'TOGGLE_TODO',
id: todo.id
});
}}
style={{
textDecoration:
todo.completed ?
'line-through' : 'none'
}}>
{todo.text}
</li>
Filtering Todos
Step1: 创建FiterLink控件
const { Component } = React;
const FilterLink = ({filter, children, currentFilter}) => {
return (
<a href='#'
onClick={e => {
e.preventDefault();
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter
})
}}>
{children}
</a>
);
}
Step2: ul元素后面添加过滤功能
<p>
Show:
{' '}
<FilterLink filter='SHOW_ALL'>ALL</FilterLink>
{' '}
<FilterLink filter='SHOW_ACTIVE'>Active</FilterLink>
{' '}
<FilterLink filter='SHOW_COMPLETED'>Completed</FilterLink>
</p>
Step3: 过滤列表方法
const getVisibleTodos = (todos, filter) => {
switch (filter){
case 'SHOW_ALL':
return todos;
case 'SHOW_COMPLETED':
return todos.filter(
t => t.completed
);
case 'SHOW_ACTIVE':
return todos.filter(
t => !t.completed
);
}
}
Step4: 显示过滤后的Todo列表
// const visibleTodos = getVisibleTodos(
// this.props.todos,
// this.props.visibilityFilter
// );
//es6写法
const { todos,visibilityFilter } = this.props;
const visibleTodos = getVisibleTodos(todos,visibilityFilter);
// <ul> {this.props.todos.map(...) 修改成visibleTodos
<ul> {visibleTodos.map(...)
<li ... >{todo.text}</li>
</ul>
Step5:
//<TodoApp todos={store.getState().todos} />
<TodoApp {...store.getState()} />
Step6: 修改FilterLink单击后取消功能
每个FilterLink属性上添加 currentFilter={visibilityFilter}
//<FilterLink filter='SHOW_ACTIVE' >Active</FilterLink>
<FilterLink filter='SHOW_ACTIVE' currentFilter={visibilityFilter}>Active</FilterLink>
const FilterLink = ({filter, children, currentFilter}) => {
if (filter === currentFilter){ //++
return <span>{children}</span>; //++
} //++
return (
<a href='#'
onClick={e => {
e.preventDefault();
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter
});
}}>
{children}
</a>
);
}
//最终代码: http://jsbin.com/bogegih/edit?js,output